package cn.sunxyz.core.factory;


import cn.sunxyz.common.utils.StringUtil;
import cn.sunxyz.common.utils.reflect.ClassUtil;
import cn.sunxyz.core.bean.BeanContext;
import cn.sunxyz.core.bean.BeanContextHelper;
import cn.sunxyz.core.factory.annotation.Scanner;
import cn.sunxyz.core.ioc.InjectHelper;
import cn.sunxyz.core.ioc.annotation.Inject;
import cn.sunxyz.core.scanner.ClassScannerHelper;

import java.util.List;
import java.util.Objects;

/**
 * Created by yangrd on 2017/5/20.
 */
public class BeanFactoryImpl implements BeanFactory {

    private static BeanFactory beanFactory = new BeanFactoryImpl();

    private BeanFactoryImpl() {
    }

    public static BeanFactory build() {
        return beanFactory;
    }

    public static BeanFactory build(Class<?> cls) {
        if (cls.isAnnotationPresent(Scanner.class)) {
            Scanner scanner = cls.getAnnotation(Scanner.class);
            beanFactory.scanner(scanner.value());
        } else {
            beanFactory.scanner(ClassUtil.getPackageName(cls));
        }
        return beanFactory;
    }


    @Override
    public BeanFactory scanner(String packagePath) {
        //获取所有class 并对托管的class示例化->调用插件对bean进行增强
        BeanContextHelper.initBeanContext(ClassScannerHelper.scanner(packagePath));
        //注入 获取实现类
        InjectHelper.inject(BeanContext.getBeanMap().entrySet(), beanField -> {
            //获取实现类
            Inject inject = beanField.getAnnotation(Inject.class);
            String beanName = inject.value();
            //根据inject指定的名字获取对应的类
            if (StringUtil.isNotEmpty(beanName)) {
                return getBean(beanName);
            } else {
                // 获取 Bean 字段对应的接口
                Class<?> interfaceClass = beanField.getType();
                //查看该类是否已经被创建实例 => 如果有直接返回该类,没有则返回该类的子类
                Object bean = getBean(interfaceClass);
                if (Objects.nonNull(bean)) {
                    return bean;
                } else {
                    // 获取对应的子类 如果有多个返回null
                    List<Class<?>> classList = BeanContextHelper.listClassBySuper(interfaceClass);
                    return classList != null ? (classList.size() == 1 ? BeanContext.getBean(classList.get(0)) : null) : null;
                }
            }
        });
        return this;
    }

    @Override
    public <T> T getBean(Class<T> clazz) {
        return BeanContext.getBean(clazz);
    }

    @Override
    public <T> T getBean(String beanName) {
        return BeanContext.getBean(beanName);
    }
}
